/*
 * MIT License
 *
 * Copyright (c) 2025 Mark·虎
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

package com.hsxxherp.key.support.util;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.query.MPJQueryWrapper;
import com.hsxxherp.key.support.model.entity.AdvancedQuery;
import com.hsxxherp.key.support.model.entity.GroupCondition;
import com.hsxxherp.key.support.model.entity.PageRequest;
import com.hsxxherp.key.support.model.entity.QueryCondition;

import java.util.List;
import java.util.Optional;

/**
 * 查询处理
 *
 * @author Mark·虎克（2486970363@qq.com）
 * @since 2025-01-25
 */
public class QueryUtils {

    private static final String ASC = "asc";

    /**
     * 通用的分页查询方法
     *
     * @param pageRequest 分页请求对象
     * @param mapper      MyBatis-Plus 的 Mapper 接口
     * @param <T>         实体类型
     * @return 分页查询结果
     */
    public static <T> IPage<T> queryPage(PageRequest<T> pageRequest, MPJBaseMapper<T> mapper) {
        Page<T> page = new Page<>(pageRequest.getPageNum(), pageRequest.getPageSize());
        MPJQueryWrapper<T> queryWrapper = buildQueryWrapper(pageRequest.getAdvancedQuery());
        return mapper.selectJoinPage(page, (Class<T>) pageRequest.getCondition().getClass(), queryWrapper);
    }

    /**
     * 构建查询条件包装器
     *
     * @param <T>           实体类型
     * @param advancedQuery 高级查询条件对象
     * @return 查询条件包装器
     */
    private static <T> MPJQueryWrapper<T> buildQueryWrapper(AdvancedQuery advancedQuery) {
        MPJQueryWrapper<T> queryWrapper = new MPJQueryWrapper<>();
        if (advancedQuery == null) {
            return queryWrapper;
        }

        Optional.ofNullable(advancedQuery.getRootGroup())
                .ifPresent(rootGroup -> buildGroupCondition(queryWrapper, rootGroup));

        Optional.ofNullable(advancedQuery.getGroupBy())
                .filter(groupBy -> !groupBy.isEmpty())
                .ifPresent(queryWrapper::groupBy);

        Optional.ofNullable(advancedQuery.getOrderBy())
                .filter(orderBy -> !orderBy.isEmpty())
                .ifPresent(orderBy -> {
                    String orderDirection = java.util.Objects.requireNonNullElse(advancedQuery.getOrderDirection(), "");
                    if (ASC.equalsIgnoreCase(orderDirection)) {
                        queryWrapper.orderByAsc(orderBy);
                    } else {
                        queryWrapper.orderByDesc(orderBy);
                    }
                });

        return queryWrapper;
    }

    /**
     * 构建分组查询条件
     *
     * @param wrapper        查询条件包装器
     * @param groupCondition 分组查询条件对象
     * @param <T>            实体类型
     */
    private static <T> void buildGroupCondition(MPJQueryWrapper<T> wrapper, GroupCondition groupCondition) {
        if ("and".equalsIgnoreCase(groupCondition.getLogic())) {
            wrapper.and(subWrapper -> {
                buildSingleConditions(subWrapper, groupCondition.getConditions());
                buildSubGroups(subWrapper, groupCondition.getSubGroups());
            });
        } else if ("or".equalsIgnoreCase(groupCondition.getLogic())) {
            wrapper.or(subWrapper -> {
                buildSingleConditions(subWrapper, groupCondition.getConditions());
                buildSubGroups(subWrapper, groupCondition.getSubGroups());
            });
        }
    }

    /**
     * 构建单个查询条件
     *
     * @param wrapper    查询条件包装器
     * @param conditions 单个查询条件列表
     * @param <T>        实体类型
     */
    private static <T> void buildSingleConditions(MPJQueryWrapper<T> wrapper, List<QueryCondition> conditions) {
        if (conditions != null) {
            for (QueryCondition condition : conditions) {
                String field = condition.getField();
                String operator = condition.getOperator();
                Object value = condition.getValue();
                String tableAlias = condition.getTableAlias();
                if (tableAlias != null && !tableAlias.isEmpty()) {
                    field = tableAlias + "." + field;
                }
                switch (operator) {
                    case "eq":
                        wrapper.eq(field, value);
                        break;
                    case "gt":
                        wrapper.gt(field, value);
                        break;
                    case "gte":
                        wrapper.ge(field, value);
                        break;
                    case "lt":
                        wrapper.lt(field, value);
                        break;
                    case "lte":
                        wrapper.le(field, value);
                        break;
                    case "like":
                        wrapper.like(field, value);
                        break;
                    default:
                        break;
                }
            }
        }
    }

    /**
     * 构建子分组查询条件
     *
     * @param wrapper   查询条件包装器
     * @param subGroups 子分组条件列表
     * @param <T>       实体类型
     */
    private static <T> void buildSubGroups(MPJQueryWrapper<T> wrapper, List<GroupCondition> subGroups) {
        if (subGroups != null) {
            for (GroupCondition subGroup : subGroups) {
                if ("and".equalsIgnoreCase(subGroup.getGroupLogic())) {
                    buildGroupCondition(wrapper, subGroup);
                } else if ("or".equalsIgnoreCase(subGroup.getGroupLogic())) {
                    wrapper.or();
                    buildGroupCondition(wrapper, subGroup);
                }
            }
        }
    }
}